package good.idea.data.excel.write;

import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.SheetConditionalFormatting;
import org.apache.poi.ss.util.PaneInformation;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.*;
import good.idea.data.excel.context.ExcelTemplateContext;
import good.idea.data.excel.context.ExcelWriteContext;
import good.idea.data.excel.entity.RowEntity;
import good.idea.data.excel.entity.TemplateTag;
import good.idea.data.utils.LangUtils;
import good.idea.data.utils.OgnlUtils;

import java.io.IOException;
import java.util.*;

/**
 * @author chm
 */
public class ExcelWriteHelper {

    public static final String VAR_NAME_ROOT_DATA = "rootData";

    public static final String VALUE_NAME_ROOT_DATA = "${rootData}";

    /**
     * 执行数据写入操作
     *
     * @param writeContext
     * @param templateContext
     * @throws Exception
     */
    public static void executeWrite(ExcelWriteContext writeContext, ExcelTemplateContext templateContext) throws Exception {
        List<RowEntity> rowEntities = templateContext.getActiveRowEntities();

        ExcelWriteTask writeTask = ExcelWriteHelper.createExcelWriteTask(writeContext, templateContext);
        writeTask.setRowEntities(rowEntities);

        Collection<Object> collection = writeTask.loadNextData(ExcelWriteHelper.VALUE_NAME_ROOT_DATA, -1);

        List<TemplateTag> templateTags = templateContext.getActiveTemplateTags();
        TemplateTag root = new TemplateTag();
        root.setStartRowIndex(-1);
        root.setEndRowIndex(rowEntities.size());
        root.getChildren().addAll(templateTags);
        root.setValue(VALUE_NAME_ROOT_DATA);
        root.setVar("");
        List<TemplateTag> rootTags = Collections.singletonList(root);
        addIndexFlag(rowEntities, rootTags, root);
        Map<String, Object> rootData = new HashMap<>();
        rootData.put(ExcelWriteHelper.VAR_NAME_ROOT_DATA, collection);
        writeData(rootTags, rootData, new HashMap<>(), writeTask);
        writeTask.getActivitySheet().setForceFormulaRecalculation(true);
    }

    /**
     * 循环写入行数据
     *
     * @param templateTags 模板标签
     * @param data         可写入的数据
     * @param writeTask    写入任务
     */
    public static void writeData(List<TemplateTag> templateTags, Object data, Object it, ExcelWriteTask writeTask) {
        List<RowEntity> rowEntities = writeTask.getRowEntities();
        for (int f = 0; f < templateTags.size(); f++) {
            TemplateTag item = templateTags.get(f);
            int start = item.getStartRowIndex();
            int end = item.getEndRowIndex();
            //取出模板数据列
            List<RowEntity> rows = getTempRowEntities(rowEntities, start, end, item);

            String ognl = writeTask.getOgnl(item.getValue());
            Object itemVal = null;
            Collection<Object> collection = new ArrayList<Object>();
            int hashCode = collection.hashCode();
            if (data != null) {
                hashCode = data.hashCode();
                itemVal = OgnlUtils.getValue(ognl, data);
                if (itemVal != null) {
                    hashCode = itemVal.hashCode();
                }
                collection = writeTask.convertData2Collection(itemVal);
            }
            rowNextRowData(writeTask, it, collection, rows, item);
        }
    }


    public static void rowNextRowData(ExcelWriteTask writeTask, Object parentData, Collection<Object> collections, List<RowEntity> rows, TemplateTag item) {
        System.out.println("parentData============" + parentData);
        for (Object subItemsVal : collections) {
            if (subItemsVal == null) {
                continue;
            }
            Object mapData = subDataBind(item.getVar(), subItemsVal);
            if (item.getStatus() != null) {
                    /*Status status = new Status();
                    status.setIndex(index);
                    status.setCount(index + 1);
                    mapData.put(item.getStatus(), status);*/
            }
            int fi = 0;
            for (RowEntity rowEntity : rows) {
                if (rowEntity.getTemplateTagFlag() < 1) {
                    if (fi > 0) {
                        continue;
                    }
                    int writeRow = writeTask.getWriteRowNum();
                    Row newRow = writeTask.createNewRow(writeRow);
                    writeTask.writeRowCells(newRow, mapData, rowEntity, writeRow);
                } else if (rowEntity.getTemplateTagFlag() == 1) {
                    fi = 1;
                    TemplateTag templateTag = rowEntity.getTemplateTag();
                    Object subData = subDataBind(item.getVar(), subItemsVal);
                    writeData(Collections.singletonList(templateTag), subData, subItemsVal, writeTask);
                } else {
                    fi = 0;
                }
            }
        }
        if (!VALUE_NAME_ROOT_DATA.equals(item.getValue())) {
            Collection<Object> items = writeTask.loadNextData(item.getValue(), parentData);
            if (LangUtils.isNotEmpty(items)) {
                rowNextRowData(writeTask, parentData, items, rows, item);
            }
        }

    }

    public static Object subDataBind(String var, Object subItemsVal) {
        Map<String, Object> data = new HashMap<String, Object>();
        if (subItemsVal != null) {
            if (LangUtils.isNotEmpty(var)) {
                data.put(var, subItemsVal);
                return data;
            } else if (subItemsVal instanceof Map) {
                return subItemsVal;
            }
        }
        return data;
    }

    public static List<RowEntity> getTempRowEntities(List<RowEntity> rowEntities, int start, int end, TemplateTag item) {
        List<RowEntity> rows = new ArrayList<RowEntity>();
        for (int i = start + 1; i < end && i < rowEntities.size(); i++) {
            RowEntity it = rowEntities.get(i);
            rows.add(it);
        }
        return rows;
    }

    public static void addIndexFlag(List<RowEntity> rowEntities, List<TemplateTag> templateTags, TemplateTag tag) {
        for (int i = 0; i < templateTags.size(); i++) {
            TemplateTag item = templateTags.get(i);
            int start = item.getTagStartIndex();
            int end = item.getTagEndIndex();
            int nuderEnd = tag.getTagEndIndex();
            setTempRowDateFlag(rowEntities, start, end, tag);
            if (end < nuderEnd) {
                setTempRowDateFlag(rowEntities, end, nuderEnd, tag);
            }
            //父子位置
            List<TemplateTag> its = item.getChildren();
            if (its.size() > 0) {
                for (int j = 0; j < its.size(); j++) {
                    TemplateTag it = its.get(j);
                    int s = it.getTagStartIndex();
                    int e = it.getTagStartIndex();
                    setTempRowDateFlag(rowEntities, s, e, it);
                    addIndexFlag(rowEntities, its, it);
                }
            }
        }
    }

    public static void setTempRowDateFlag(List<RowEntity> rowEntities, int start, int end, TemplateTag tag) {
        List<RowEntity> items = rowEntities;
        for (int i = start + 1; i < end && i < items.size(); i++) {
            RowEntity it = items.get(i);
            it.setUnderTemplateTag(tag);
        }
    }

    /**
     * 创建写入任务
     *
     * @param writeContext
     * @param templateContext
     * @return
     */
    public static ExcelWriteTask createExcelWriteTask(ExcelWriteContext writeContext, ExcelTemplateContext templateContext) throws IOException {

        SXSSFWorkbook outWorkbook = writeContext.getOutWorkbook();

        SXSSFSheet sheet = outWorkbook.getSheetAt(writeContext.getActivitySheetIndex());
        sheet.setAutobreaks(true);

        ExcelWriteTask writeTask = new ExcelWriteTask();
        writeTask.setActivitySheet(sheet);
        writeContext.setActivitySheet(writeTask.getActivitySheet());
        // writeTask.setSheetIndex(index);

        writeTask.setActivitySheet(writeContext.getActivitySheet());
        writeTask.setWriteContext(writeContext);
        writeTask.setTempSheetIndex(templateContext.getActivitySheetIndex());

        return writeTask;
    }

    //sheet 样式拷贝
    private static void copySheetsStyle(SXSSFSheet newSheet, XSSFSheet sheet) {
        //公式计算
        newSheet.setForceFormulaRecalculation(true);
        //sheet tab颜色
        XSSFColor tabColor = sheet.getTabColor();
        if (Objects.nonNull(tabColor)) {
            newSheet.setTabColor(sheet.getTabColor());
        }
        //条件表达式
        XSSFSheetConditionalFormatting scf = sheet.getSheetConditionalFormatting();
        SheetConditionalFormatting toSheetConditionFormat = newSheet.getSheetConditionalFormatting();
        for (int i = 0; i < scf.getNumConditionalFormattings(); i++) {
            toSheetConditionFormat.addConditionalFormatting(scf.getConditionalFormattingAt(i));
        }
        //冻结行列信息
        PaneInformation paneInformation = sheet.getPaneInformation();
        if (Objects.nonNull(paneInformation)) {
            newSheet.createFreezePane(paneInformation.getHorizontalSplitPosition(), paneInformation.getVerticalSplitPosition()
                    , paneInformation.getHorizontalSplitTopRow(), paneInformation.getVerticalSplitLeftColumn());
        }
    }


    public static ExcelWriteContext crateWriteContext() {
        ExcelWriteContext context = new ExcelWriteContext();
        return context;
    }
}
